﻿//-----------------------------------------------------------------------
// <Copyright>
// * Copyright (C) 2022 RuYiAdmin All Rights Reserved
// </Copyright>
//-----------------------------------------------------------------------

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Minio.DataModel.Args;
using Newtonsoft.Json;
using RuYiAdmin.Net.DataModel.DataTransformationModel.Sys;
using RuYiAdmin.Net.SystemService.BusinessServiceExtension;
using RuYiAdmin.Net.UniversalFoundation.Configurations;
using RuYiAdmin.Net.UniversalFoundation.Constants.Sys;
using RuYiAdmin.Net.UniversalFoundation.Contexts;
using RuYiAdmin.Net.UniversalFoundation.Enums.Business;
using RuYiAdmin.Net.UniversalFoundation.Utils;
using System;
using System.IO;

namespace RuYiAdmin.Net.WebApi.RuYiAdminCode.RuYiAdminAnnotation
{
    /// <summary>
    /// 审计日志过滤器
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class RuYiAdminOperationLogAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// 操作类型
        /// </summary>
        private OperationType OperationType { get; set; }

        /// <summary>
        /// 行为描述信息
        /// </summary>
        private string Description { get; set; }

        /// <summary>
        /// 是否忽略结果
        /// </summary>
        private bool IgnoredResult { get; set; } = false;

        public RuYiAdminOperationLogAttribute(OperationType operationType, string description = null, bool IgnoredResult = false)
        {
            this.OperationType = operationType;
            this.Description = description;
            this.IgnoredResult = IgnoredResult;
        }

        public override async void OnResultExecuted(ResultExecutedContext context)
        {
            base.OnResultExecuted(context);

            //判断审计日志记录开关是否开启
            if (!RuYiGlobalConfig.LogConfig.IsEnabled)
            {
                return;
            }

            var token = context.HttpContext.GetToken();
            //获取用户
            var user = RuYiRedisContext.Get<SysUserDTO>(token);
            if (user == null)
            {
                context.Exception = new Exception(ExceptionMessage.InvalidTokenExceptionMessage);
                return;
            }

            #region 监控信息入库

            var log = SysLogServiceExtension.GetSysLog(context.HttpContext);

            //字段赋值
            log.OperationType = this.OperationType;
            if (!string.IsNullOrEmpty(this.Description))
            {
                log.Remark = this.Description;
            }

            #region 设置返回值

            var isFileStream = context.Result.GetType().Equals(typeof(Microsoft.AspNetCore.Mvc.FileStreamResult));
            var isFile = context.Result.GetType().Equals(typeof(Microsoft.AspNetCore.Mvc.FileResult));
            var forbidenResult = context.Result.GetType().Equals(typeof(Microsoft.AspNetCore.Mvc.ForbidResult));
            if (!isFileStream && !isFile && !forbidenResult)
            {
                var result = JsonConvert.SerializeObject(((Microsoft.AspNetCore.Mvc.ObjectResult)context.Result).Value);
                if (result != null && !this.IgnoredResult)
                {
                    if (RuYiGlobalConfig.LogConfig.SupportMongoDB || RuYiGlobalConfig.LogConfig.SupportElasticsearch || RuYiGlobalConfig.LogConfig.SupportMeilisearch)
                    {
                        log.Result = result;
                    }
                    else
                    {
                        if (result.Length > 2000)
                        {
                            log.Result = result.Substring(0, 2000) + "...";

                            String fileName = log.Id + ".txt";
                            var monitoringLogsPath = string.Join(string.Empty, RuYiGlobalConfig.DirectoryConfig.GetMonitoringLogsPath(), "/" + fileName);//返回结果落盘
                            var file = new FileStream(monitoringLogsPath, FileMode.Create);
                            byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(result);
                            file.Write(byteArray, 0, byteArray.Length);
                            file.Flush();
                            file.Close();

                            if (RuYiGlobalConfig.MinioConfig.IsEnabled)
                            {
                                var putObjectArgs = new PutObjectArgs()
                                    .WithBucket(RuYiGlobalConfig.MinioConfig.BucketName)
                                    .WithObject(RuYiGlobalConfig.DirectoryConfig.GetMinioMonitoringLogsPath() + "/" + fileName)
                                    .WithFileName(monitoringLogsPath);
                                await RuYiMinioContext.Instance.PutObjectAsync(putObjectArgs);
                                RuYiFileContext.DeleteFile(monitoringLogsPath); //删除本地文件
                            }
                        }
                        else
                        {
                            log.Result = result;
                        }
                    }
                }
            }

            #endregion

            //记录审计日志
            await log.WriteAsync();

            #endregion
        }
    }
}
